﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

//using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows;
using System.Media;
using Coding4Fun.Kinect.Wpf.Controls;
using System.Text.RegularExpressions;
using System.Windows.Media;

namespace Hugo
{
    public class SlidingTileUIPage : UIPage
    {
        int selectedIndex;
        List<UIOption> pages;
        Dictionary<String, Rectangle> pageNameToSymbolMap;

        int currentpos = 0;
        int shiftamount = 400;

        double iconY;

        Label currentSelectionLabel;

        const double OPACITY_UNSELECTED = 0.15;
        const double OPACITY_SELECTED = 1;

        Canvas IconCanvas;

        static int nextIconCanvasID = 0;
        static int numOptionsVisibleAtATime = 3;

        public SlidingTileUIPage(String name, BitmapSource iconSource)
            : this(name,iconSource,160)
        {
        }

        public SlidingTileUIPage(String name, BitmapSource iconSource, int labelFontSize)
            : base(name, iconSource)
        {
            
            iconY = GlobalSettings.EffectiveScreenMiddleY - GlobalSettings.ICON_HEIGHT_SELECTED / 2;
            
            IconCanvas = new Canvas();
            IconCanvas.Name = "slidingtileuipage" + (nextIconCanvasID++);
            MainWindow.RegisterName(IconCanvas.Name, IconCanvas);
            this.PageCanvas.Children.Add(IconCanvas);

            this.shiftamount = GlobalSettings.ICON_WIDTH_SELECTED + GlobalSettings.ICON_BUFFER;

            pages = new List<UIOption>();
            pageNameToSymbolMap = new Dictionary<String, Rectangle>();

            Grid g = new Grid();
            g.Width = GlobalSettings.EffectiveScreenMiddleX * 2;
            this.PageCanvas.Children.Add(g);

            descriptionLabel = new Label();
            descriptionLabel.Foreground = new SolidColorBrush(GlobalSettings.BreadcrumbColor);
            descriptionLabel.FontSize = GlobalSettings.SelectedLabelFontSize;
            descriptionLabel.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
            descriptionLabel.Margin = new Thickness(0, GlobalSettings.BreadcrumbPosition, 0, 0);
            descriptionLabel.Content = Translate.translate(this.getDescription());

            currentSelectionLabel = new Label();
            currentSelectionLabel.Foreground = new SolidColorBrush(GlobalSettings.TextColor);
            currentSelectionLabel.FontSize = GlobalSettings.SelectedLabelFontSize;
            currentSelectionLabel.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
            currentSelectionLabel.Margin = new Thickness(0, GlobalSettings.SelectedLabelPosition, 0, 0);

            g.Children.Add(descriptionLabel);
            g.Children.Add(currentSelectionLabel);
        }

        private void setTransparent(Rectangle r)
        {
            r.Opacity = 0;
        }

        private void setOpaque(Rectangle r)
        {
            r.Opacity = 1;
        }

        static int counter = 0;

        public void addUIOption(UIOption page)
        {
            pages.Add(page);

            Rectangle rect = Util.getSymbol(page.IconSource);

            pageNameToSymbolMap.Add(page.Name, rect);

            setTransparent(rect);

            Regex rgx = new Regex("[^a-zA-Z0-9]");
            rect.Name = "listuipage" + rgx.Replace(page.Name, "") + pages.Count + "_rect" + (counter++);
            this.MainWindow.RegisterName(rect.Name, rect);

            IconCanvas.Children.Add(rect);

            Point p = getCenterOfRectangleAtIndex(pages.Count-1);
            Canvas.SetLeft(rect, p.X);
            Canvas.SetTop(rect, p.Y);

            this.resizeOnCenter(rect, GlobalSettings.ICON_WIDTH_SELECTED, GlobalSettings.ICON_HEIGHT_SELECTED);

            rect.Opacity = OPACITY_UNSELECTED;
        }

        private Point getCenterOfRectangleAtIndex(int index) {
            double x = (System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width / 2) - GlobalSettings.ICON_WIDTH_SELECTED / 2 + (GlobalSettings.ICON_WIDTH_SELECTED * index) + index * GlobalSettings.ICON_BUFFER;
            double y = this.iconY;
            return new Point(x, y);
        }

        private Rectangle getSelectedRectangle()
        {
            return pageNameToSymbolMap[pages[selectedIndex].Name];
        }

        private UIOption getSelectedPage()
        {
            return pages[selectedIndex];
        }

        private Rectangle getRectangleAt(int index)
        {
            return pageNameToSymbolMap[pages[index].Name];
        }

        public override void shiftRight()
        {
            int newIndex = this.selectedIndex + 1;
            if (newIndex == pages.Count) { newIndex = 0; }
            setSelectedIndex(newIndex);
        }

        private void speakPageSelectedAtIndex(int index)
        {
            Sounds.speakMessageAsync(pages[index].Name);
        }

        public override void shiftLeft()
        {
            int newIndex = this.selectedIndex - 1;
            if (newIndex == -1) { newIndex = pages.Count - 1; }
            setSelectedIndex(newIndex);
        }

        private static Action EmptyDelegate = delegate() { };

        public void setSelectedIndex(int index)
        {
            //if (index == this.selectedIndex) { return; }
            if (pages.Count == 0) { return; }
            
           getSelectedRectangle().Opacity = OPACITY_UNSELECTED;

            int diff = this.selectedIndex - index;

            int oldIndex = this.selectedIndex;
            this.selectedIndex = index;

            currentSelectionLabel.Visibility = System.Windows.Visibility.Hidden;

            String name = pages[this.selectedIndex].Name;
            if (pages[this.selectedIndex].CanTranslate)
            {
                name = Translate.translate(name);
            }

            currentSelectionLabel.Content = name;//.ToUpper();
            // need to rerender to get updated width
            currentSelectionLabel.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
            Canvas.SetLeft(currentSelectionLabel, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width / 2 - currentSelectionLabel.ActualWidth / 2);
            currentSelectionLabel.Visibility = System.Windows.Visibility.Visible;

            resizeOnCenter(getRectangleAt(oldIndex), GlobalSettings.ICON_WIDTH_SELECTED, GlobalSettings.ICON_HEIGHT_SELECTED);
          //  DoubleAnimation fadeOutSlightlyAnimation = AnimationFactory.getScaleAnimation(OPACITY_SELECTED, OPACITY_UNSELECTED);
           // AnimationFactory.runStoryBoard(this.MainWindow,fadeOutSlightlyAnimation, getRectangleAt(oldIndex).Name, new PropertyPath(Canvas.OpacityProperty));

            resizeOnCenter(getSelectedRectangle(), GlobalSettings.ICON_WIDTH_SELECTED, GlobalSettings.ICON_HEIGHT_SELECTED);
           // DoubleAnimation fadeInSlightlyAnimation = AnimationFactory.getScaleAnimation(OPACITY_UNSELECTED, OPACITY_SELECTED);
           // AnimationFactory.runStoryBoard(this.MainWindow, fadeInSlightlyAnimation, getSelectedRectangle().Name, new PropertyPath(Canvas.OpacityProperty));

            getSelectedRectangle().Opacity = OPACITY_SELECTED;

            for (int i = 0; i < pages.Count; i++)
            {
                int diffToSelected = (int) Math.Abs(Math.Ceiling((double)(i - this.selectedIndex)));

                double currentOpacity = pageNameToSymbolMap[pages[i].Name].Opacity;
                double targetOpacity = 0;

                if (diffToSelected == 0)
                {
                    targetOpacity = OPACITY_SELECTED;
                }
                else if (diffToSelected > numOptionsVisibleAtATime / 2)
                {
                    targetOpacity = 0;
                }
                else
                {
                    targetOpacity = OPACITY_UNSELECTED;
                }

                if (targetOpacity != currentOpacity)
                {
                    //pageNameToSymbolMap[pages[i].Name].Opacity = targetOpacity;
                    DoubleAnimation opacityAnimation = AnimationFactory.getScaleAnimation(currentOpacity, targetOpacity);
                    AnimationFactory.runStoryBoard(this.MainWindow, opacityAnimation, this.pageNameToSymbolMap[pages[i].Name].Name, new PropertyPath(Canvas.OpacityProperty));
                }
            }

            DoubleAnimation myDoubleAnimation = AnimationFactory.getShiftAnimation(currentpos, diff * shiftamount);

            currentpos = currentpos + shiftamount * diff;
            
            Storyboard myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            Storyboard.SetTargetName(myDoubleAnimation, IconCanvas.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Canvas.LeftProperty));

            myStoryboard.Begin(this.MainWindow);

            if (diff != 0)
            {
                if (GlobalSettings.isBlind)
                {
                    //Sounds.speakMessage
                    speakPageSelectedAtIndex(index);

                }
                else
                {
                    Sounds.playSound(Sounds.Sound.Navigate);
                }
            }
        }

        public override bool respondToClick(MouseButtonEventArgs e)
        {
            HandCursor.getInstance().setHovering(false);

            if (indexOfSelectedImage != -1)
            {
                if (selectedIndex == indexOfSelectedImage)
                {
                    pages[selectedIndex].wasSelected();
                }
                else
                {
                    this.setSelectedIndex(indexOfSelectedImage);
                }
                Console.WriteLine("User clicked on " + indexOfSelectedImage + " " + pages[indexOfSelectedImage].Name);

                return true;
            }

            return false;
        }

        DispatcherTimer _timer;
        int indexOfSelectedImage;

        public override bool setCursorPosition(System.Windows.Point p)
        {
            bool isHovering = false;
            bool wasHovering = HandCursor.getInstance().isHovering();

            indexOfSelectedImage = getIndexOfImageAtPosition(p);

            if (indexOfSelectedImage != -1)
            {
                isHovering = true;
            }

            //HandCursor.getInstance().setHovering(isHovering);

            if (wasHovering && !isHovering || _timer == null)
            {
                if (_timer != null) { _timer.Stop(); }

                _timer = new DispatcherTimer();
                _timer.Interval = TimeSpan.FromMilliseconds(4000);
                _timer.Tag = this;
                _timer.Tick += new EventHandler(notificationTimerElapsed);
                _timer.Start();
            }

            return isHovering;
            //base.setCursorPosition(p);
        }

        static void notificationTimerElapsed(object sender, EventArgs e)
        {
            //we want this event handler executed just once
            DispatcherTimer thisTimer = (DispatcherTimer)sender;
            SlidingTileUIPage page = (SlidingTileUIPage)thisTimer.Tag;
            if (!HandCursor.getInstance().isHovering())
            {
                //TODO:uncomment to autoscroll
                page.shiftRight();
            }
        }

        private int getIndexOfImageAtPosition(Point p)
        {
            int index = -1;

            int i = 0;
            foreach (UIOption o in pages)
            {
                Rectangle im = pageNameToSymbolMap[o.Name];

                Point pos = im.PointToScreen(new Point());

                double rX = pos.X - HandCursor.handSize / 2;
                double rY = pos.Y - HandCursor.handSize / 2;
                double rX2 = rX + im.ActualWidth;
                double rY2 = rY + im.ActualHeight;

                if (rX < p.X && rY < p.Y && rX2 > p.X && rY2 > p.Y)
                {
                    index = i;
                    break;
                }
                i++;
            }

            indexOfSelectedImage = index;

            return index;
        }


        public void clearPage()
        {
            pages.RemoveRange(0, pages.Count);

            String[] keys = new String[pageNameToSymbolMap.Keys.Count];
            int keyNo = 0;
            foreach (String key in pageNameToSymbolMap.Keys)
            {
                keys[keyNo++] = key;
            }

            foreach (String key in keys)
            {
                Rectangle r = pageNameToSymbolMap[key];
                IconCanvas.Children.Remove(r);
                pageNameToSymbolMap.Remove(key);
            }

        }

        private void resizeOnCenter(Rectangle r, int newWidth, int newHeight)
        {
            DoubleAnimation widthAnimation = AnimationFactory.getScaleAnimation(r.ActualWidth, newWidth);
            DoubleAnimation heightAnimation = AnimationFactory.getScaleAnimation(r.ActualHeight, newHeight);

            double oldCenterX = Canvas.GetLeft(r) + r.ActualWidth / 2;
            double oldCenterY = Canvas.GetTop(r) + r.ActualHeight / 2;
            double newCenterX = Canvas.GetLeft(r) + newWidth / 2;
            double newCenterY = Canvas.GetTop(r) + newHeight / 2;

            DoubleAnimation xAnimation = AnimationFactory.getScaleAnimation(oldCenterX, newCenterX);
            DoubleAnimation yAnimation = AnimationFactory.getScaleAnimation(oldCenterY, newCenterY);

            Storyboard widthStoryBoard = new Storyboard();
            widthStoryBoard.Children.Add(widthAnimation);
            Storyboard.SetTargetName(widthAnimation, r.Name);
            Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Rectangle.WidthProperty));
            //widthStoryBoard.Begin(this.MainWindow);

            Storyboard heightStoryboard = new Storyboard();
            heightStoryboard.Children.Add(heightAnimation);
            Storyboard.SetTargetName(heightAnimation, r.Name);
            Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(Rectangle.HeightProperty));
            //heightStoryboard.Begin(this.MainWindow);



            /*
            double oldCenterX = Canvas.GetLeft(r) + r.Width / 2;
            double oldCenterY = Canvas.GetTop(r) + r.Height / 2;

            r.Width = newWidth;
            r.Height = newHeight;

            Canvas.SetLeft(r, oldCenterX - r.Width / 2);
            Canvas.SetTop(r, oldCenterY - r.Height / 2);
             */
        }
        
        private Rectangle getSymbol(Uri u)
        {
            Rectangle item = new Rectangle();
            item.Height = GlobalSettings.ICON_HEIGHT_SELECTED;
            item.Width = GlobalSettings.ICON_WIDTH_SELECTED;
            System.Windows.Media.ImageBrush myBrush = new System.Windows.Media.ImageBrush();
            myBrush.ImageSource = new BitmapImage(u);
            item.Fill = myBrush;

            return item;
        }

        public List<UIOption> getUIPages()
        {
            return this.pages;
        }

        public override void setPage()
        {
            descriptionLabel.Content = Translate.translate(this.getDescription());
            this.setSelectedIndex(this.selectedIndex);
            
            if (_timer != null)
            {
                _timer.Start();
            }

            base.setPage();
        }

        public override void unSetPage()
        {
            if (_timer != null)
            {
                _timer.Stop();
            }

            base.unSetPage();
        }

        String cursorSelectionPageName;
        int cursorCountDown;
        const int HOLD_TIME = 5; //seconds
        
        Storyboard flashAnimationStoryboard;
        private Label descriptionLabel;

        public void startFlashing(Rectangle r) {

            if (flashAnimationStoryboard != null)
            {
                flashAnimationStoryboard.Stop(this.MainWindow);
            }

            DoubleAnimation flashAnimation = AnimationFactory.getFastContinuousFadeAnimation(r.Opacity,r.Opacity*0.4);

            flashAnimationStoryboard = new Storyboard();
            flashAnimationStoryboard.Children.Add(flashAnimation);
            Storyboard.SetTargetName(flashAnimation, r.Name);
            Storyboard.SetTargetProperty(flashAnimation, new PropertyPath(Canvas.OpacityProperty));

            flashAnimationStoryboard.Begin(this.MainWindow, true);
        }

        /*
        public override void setCursorPosition(Point p)
        {
            bool isOverSomething = false;

            foreach (String pageName in pageNameToSymbolMap.Keys) {
                
                Rectangle r = pageNameToSymbolMap[pageName];
                double rX = Canvas.GetLeft(r)+currentpos;
                double rY = Canvas.GetTop(r);
                double rX2 = rX + r.ActualWidth;
                double rY2 = rY + r.ActualHeight;

                
                if (rX < p.X && rY < p.Y && rX2 > p.X && rY2 > p.Y)
                {
                    isOverSomething = true;

                    if (cursorSelectionPageName == null || !cursorSelectionPageName.Equals(pageName))
                    {
                        startFlashing(r);

                        cursorCountDown = HOLD_TIME;
                        cursorSelectionPageName = pageName;
                    }

                    //Sounds.speekMessage(cursorCountDown + "");
                    cursorCountDown--;

                    if (cursorCountDown == 0)
                    {
                        //Sounds.speekMessage("Should select " + pageName);
                        cursorSelectionPageName = null;
                        int index = indexOfPage(pageName);

                        if (index == indexOfPage(getSelectedPage().Name))
                        {
                            pushSelectedPage();
                        }
                        else
                        {
                            setSelectedIndex(index);
                        }
                    }
                }
            }

            if (!isOverSomething)
            {
                if (flashAnimationStoryboard != null)
                {
                    flashAnimationStoryboard.Stop(this.MainWindow);
                }
            }
        }
         */

        private int indexOfPage(String pageName)
        {
            for (int i = 0; i < pages.Count; i++)
            {
                if (pages[i].Name.Equals(pageName))
                {
                    return i;
                }
            }

            return -1;
        }

        public override bool respondToKey(KeyEventArgs e)
        {
            if (e.Key == Key.Left)
            {
                shiftLeft();
            }
            else if (e.Key == Key.Right)
            {

                shiftRight();
            }
            else if (e.Key == Key.Enter)
            {
                //Sounds.playSound(Sounds.Sound.Accept);
                pushSelectedPage();
                
            }
            else if (e.Key == Key.Back)
            {

                //Sounds.playSound(Sounds.Sound.Accept);

                MainWindow.popPage();
            }
            else
            {
                return false;
            }

            return true;
        }

        private void pushSelectedPage()
        {
            if (GlobalSettings.isBlind)
            {
                Sounds.speakMessage("Selecting");
            }

            UIOption selectedPage = getSelectedPage();
            selectedPage.wasSelected();
        }
    }
}
